package networkSimulation.simulation.animals.framework

import networkSimulation.framework.{Graph, Edge, Node}
import util.Random

/**
 * This class represents an Animal.
 * Each animal has a name.
 * An animal is subtype of Node.
 *
 * @author  Tim Caljé
 *          Jeroen De Raedt
 *          Jorick Van Aken
 */
abstract class Animal(name : String) extends Node(name){

  /**
   * This property marks the animal as dead.
   */
  var isDead = false

  /**
   * This property represents the number of days that the animal hasn't eaten
   */
  var nbDaysWithoutFood = 0

  /**
   * This property represents the default number of days that the animal can live without eating.
   */
  val daysWithoutFoodLimit = 10000

  /**
   * Eat another animal.
   *
   * @param animal
   *        The animal that will be eaten.
   * @post  The given animal will be marked as dead
   *        | animal.die
   * @post  The counter of the number of days without food will be reset
   *        | nbDaysWithoutFood = 0
   */
    def eat[A <% Animal](animal : A){
      nbDaysWithoutFood = 0
      animal.die
    }

  /**
   * The animal dies.
   *
   * @post  Mark the animal as dead
   *        | this.isDead = true
   */
    def die(){
      this.isDead = true
    }

  /**
   * Increment the number of days the animal hasn't eaten.
   *
   * @post  the number of days the animal hasn't eaten will be incremented by 1.
   *        | this.nbDaysWithoutFood += 1
   * @post  if the daysWithoutFoodLimit is reached, then the animal starves to death.
   *        | if (nbDaysWithoutFood >= daysWithoutFoodLimit)
   *        |   die
   */
  def incrementDaysWithoutFood() {
    nbDaysWithoutFood += 1
    if (nbDaysWithoutFood >= daysWithoutFoodLimit)
      die()
  }

  /**
   * Custom simulation method.
   *
   * @param graph
   *        The graph of which the animal is part of
   * @post  If the animal has no neighbours, increment its number of days without food
   * @post  If the animal has neighbours, try to eat them
   *          on success: eat the animal
   *          on failure: increment the number of days without food
   */
  override def simulate[N<%Node, E<%Edge[N]](graph: Graph[N, E]) {
    if (graph.getNeighbours(this.asInstanceOf[N]).map(_.asInstanceOf[Animal]).toList.length == 0) {
        incrementDaysWithoutFood
    } else {
         for(animal: Animal <- graph.getNeighbours(this.asInstanceOf[N]).map(_.asInstanceOf[Animal]).toList if (animal.isDead == false)) {
            val hunt = graph.getEdge(this.asInstanceOf[N],animal.asInstanceOf[N])
            for (edge : Hunt[Animal] <- hunt.map(_.asInstanceOf[Hunt[Animal]])){
              val suc = new Random().nextInt(edge.successRate)
              val success : Boolean = (suc == 1)
              if (success){
                 eat(animal)
              }else {
                 incrementDaysWithoutFood()
              }
            }
        }
    }
  }
           
}